package com.huan.netty01.socket;

import com.huan.netty01.netty.MyServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @author 作者:刘欢
 * @create 2024-03-19-15:28
 *
 * 服务端
 */
public class Socket {

    public static void main(String[] args) {
        //创建两个线程组 boosGroup、workerGroup
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

            try {
                //创建服务端的启动对象，设置参数
                ServerBootstrap bootstrap = new ServerBootstrap();
                //设置两个线程组boosGroup和workerGroup
                bootstrap.group(bossGroup, workerGroup)
                        //设置服务端通道实现类型  异步非阻塞的服务器端 TCP Socket 连接 NioServerSocketChannel 因为是异步非阻塞的。所以是首选。  同步： OioServerSocketChannel： 同步阻塞的服务器端 TCP Socket 连接。
                        .channel(NioServerSocketChannel.class)
                        /**
                         * 设置线程队列得到连接个数  option()设置的是服务端用于接收进来的连接，也就是boosGroup线程。
                         * ServerSocketChannel参数，也就是option()常用参数：
                         * SO_BACKLOG Socket参数，服务端接受连接的队列长度，如果队列已满，客户端连接将被拒绝。默认值，Windows为200，其他为128。
                         */
                        .option(ChannelOption.SO_BACKLOG, 200)
                        /**
                         * 设置保持活动连接状态     childOption()是提供给父管道接收到的连接，也就是workerGroup线程。
                         * SocketChannel参数，也就是childOption()常用的参数：
                         * SO_RCVBUF Socket参数，TCP数据接收缓冲区大小。
                         * TCP_NODELAY TCP参数，立即发送数据，默认值为Ture。
                         * SO_KEEPALIVE Socket参数，连接保活，默认值为False。启用该功能时，TCP会主动探测空闲连接的有效性。
                         */
                        .childOption(ChannelOption.SO_KEEPALIVE, true)
                        //使用匿名内部类的形式初始化通道对象  childHandler()方法需要初始化通道  实例化一个ChannelInitializer
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            //重写initChannel()初始化通道的方法  装配流水线就是在这个地方进行
                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                //给pipeline管道设置处理器
                                socketChannel.pipeline().addLast(new MyServerHandler());
                            }
                        });//给workerGroup的EventLoop对应的管道设置处理器

                System.out.println("服务端已经准备就绪............等待链接...........");
                //绑定端口号，启动服务端 bind() 提供用于服务端或者客户端绑定服务器地址和端口号，默认是异步启动。如果加上sync()方法则是同步。
                ChannelFuture channelFuture = bootstrap.bind(8888).sync();
                //对关闭通道进行监听
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            finally {
                //释放掉所有的资源，包括创建的线程
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
}
